001 /*
002 * Copyright 2004 Stephen J. McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.transit.monitor;
020
021 import java.net.URL;
022 import java.util.logging.Logger;
023 import java.util.logging.Level;
024
025 import net.dpml.lang.PID;
026
027 /**
028 * Generic adapter that redirects monitor events to a logging channel.
029 *
030 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
031 * @version 1.0.1
032 */
033 public class LoggingAdapter implements Adapter
034 {
035 // ------------------------------------------------------------------------
036 // static
037 // ------------------------------------------------------------------------
038
039 /**
040 * Constant kb value.
041 */
042 private static final int KBYTE = 1024;
043
044 /**
045 * The logging channel.
046 */
047 private static final String CATEGORY = "";
048
049 private static final PID ID = new PID();
050
051 // ------------------------------------------------------------------------
052 // state
053 // ------------------------------------------------------------------------
054
055 private Logger m_logger;
056
057 // ------------------------------------------------------------------------
058 // constructor
059 // ------------------------------------------------------------------------
060
061 /**
062 * Creation of a new console adapter that is used to redirect transit events
063 * the system output stream.
064 */
065 public LoggingAdapter()
066 {
067 this( Logger.getLogger( CATEGORY ) );
068 }
069
070 /**
071 * Creation of a new console adapter that is used to redirect transit events
072 * the system output stream.
073 * @param logger the assigned logging channel
074 */
075 public LoggingAdapter( Logger logger )
076 {
077 m_logger = logger;
078 }
079
080 /**
081 * Creation of a new console adapter that is used to redirect transit events
082 * the system output stream.
083 * @param category the logging channel category name
084 */
085 public LoggingAdapter( String category )
086 {
087 m_logger = Logger.getLogger( category );
088 }
089
090 // ------------------------------------------------------------------------
091 // Adapter
092 // ------------------------------------------------------------------------
093
094 /**
095 * Return TRUE is trace level logging is enabled.
096 * @return the enabled state of trace logging
097 */
098 public boolean isTraceEnabled()
099 {
100 return m_logger.isLoggable( Level.FINER );
101 }
102
103 /**
104 * Return TRUE is debug level logging is enabled.
105 * @return the enabled state of debug logging
106 */
107 public boolean isDebugEnabled()
108 {
109 return m_logger.isLoggable( Level.FINE );
110 }
111
112 /**
113 * Return TRUE is info level logging is enabled.
114 * @return the enabled state of info logging
115 */
116 public boolean isInfoEnabled()
117 {
118 return m_logger.isLoggable( Level.INFO );
119 }
120
121 /**
122 * Return TRUE is error level logging is enabled.
123 * @return the enabled state of error logging
124 */
125 public boolean isWarnEnabled()
126 {
127 return m_logger.isLoggable( Level.WARNING );
128 }
129
130 /**
131 * Return TRUE is error level logging is enabled.
132 * @return the enabled state of error logging
133 */
134 public boolean isErrorEnabled()
135 {
136 return m_logger.isLoggable( Level.SEVERE );
137 }
138
139 /**
140 * Log a debug message is trace mode is enabled.
141 * @param message the message to log
142 */
143 public void trace( String message )
144 {
145 if( isTraceEnabled() )
146 {
147 m_logger.finer( message );
148 }
149 }
150
151 /**
152 * Log a debug message is debug mode is enabled.
153 * @param message the message to log
154 */
155 public void debug( String message )
156 {
157 if( isDebugEnabled() )
158 {
159 m_logger.fine( message );
160 }
161 }
162
163 /**
164 * Log a info level message.
165 * @param message the message to log
166 */
167 public void info( String message )
168 {
169 if( isInfoEnabled() )
170 {
171 m_logger.info( message );
172 }
173 }
174
175 /**
176 * Record a warning message.
177 * @param message the warning message to record
178 */
179 public void warn( String message )
180 {
181 if( isWarnEnabled() )
182 {
183 m_logger.warning( message );
184 }
185 }
186
187 /**
188 * Record a warning message.
189 * @param message the warning message to record
190 * @param cause the causal exception
191 */
192 public void warn( String message, Throwable cause )
193 {
194 if( isWarnEnabled() )
195 {
196 m_logger.log( Level.WARNING, message, cause );
197 }
198 }
199
200 /**
201 * Log a error message.
202 * @param message the message to log
203 */
204 public void error( String message )
205 {
206 if( isErrorEnabled() )
207 {
208 m_logger.log( Level.SEVERE, message );
209 }
210 }
211
212 /**
213 * Log a error message.
214 * @param message the message to log
215 * @param e the causal exception
216 */
217 public void error( String message, Throwable e )
218 {
219 if( isErrorEnabled() )
220 {
221 m_logger.log( Level.SEVERE, message, e );
222 }
223 }
224
225 /**
226 * Return a child logger.
227 * @param category the sub-category name.
228 * @return the child logging channel
229 */
230 public net.dpml.util.Logger getChildLogger( String category )
231 {
232 if( ( null == category ) || "".equals( category ) )
233 {
234 return this;
235 }
236 else
237 {
238 String name = m_logger.getName();
239 String path = trim( name + "." + category );
240 return new LoggingAdapter( Logger.getLogger( path ) );
241 }
242 }
243
244 private String trim( String path )
245 {
246 if( path.startsWith( "." ) )
247 {
248 return trim( path.substring( 1 ) );
249 }
250 else if( ".".equals( path ) )
251 {
252 return "";
253 }
254 else
255 {
256 return path;
257 }
258 }
259
260 /**
261 * Handle download notification.
262 * @param resource the resource under attention
263 * @param total the estimated download size
264 * @param count the progress towards expected
265 */
266 public void notify( URL resource, int total, int count )
267 {
268 String path = resource.toString();
269 if( path.startsWith( "file:" ) )
270 {
271 return;
272 }
273 if( isAnt() || ( "true".equals( System.getProperty( "dpml.subprocess" ) ) ) )
274 {
275 if( count == 0 )
276 {
277 info( "downloading [" + resource + "] (" + getFranctionalValue( total ) + ")" );
278 }
279 return;
280 }
281
282 if( isInfoEnabled() )
283 {
284 String max = getFranctionalValue( total );
285 String value = getFranctionalValue( count );
286 int pad = max.length() - value.length();
287 String level = getLogHeader();
288 String process = getProcessHeader();
289 StringBuffer buffer = new StringBuffer( process + level );
290 String name = path.substring( path.lastIndexOf( '/' ) + 1 );
291 buffer.append( "(" + m_logger.getName() + "): " );
292 buffer.append( "retrieving: " + name + " " );
293 for( int i=0; i < pad; i++ )
294 {
295 buffer.append( " " );
296 }
297 buffer.append( value );
298 buffer.append( "k/" );
299 if( total == 0 )
300 {
301 buffer.append( "?" );
302 }
303 else
304 {
305 buffer.append( max );
306 buffer.append( "k\r" );
307 }
308 if( total == count )
309 {
310 System.out.println( buffer.toString() );
311 }
312 else
313 {
314 System.out.print( buffer.toString() );
315 }
316 }
317 }
318
319 /**
320 * Internal utility to return the locaized logging level name.
321 * @return the localized name
322 */
323 private String getLogHeader()
324 {
325 StringBuffer buffer = new StringBuffer();
326 buffer.append( "[" );
327 Level level = getLoggerLevel( m_logger );
328 buffer.append( level.getLocalizedName() );
329 buffer.append( " " );
330 String tag = buffer.toString();
331 return tag.substring( 0, EIGHT ) + "] ";
332 }
333
334 private String getProcessHeader()
335 {
336 StringBuffer buffer = new StringBuffer();
337 buffer.append( "[" );
338 buffer.append( ID.getValue() );
339 buffer.append( " " );
340 String tag = buffer.toString();
341 return tag.substring( 0, PROCESS_HEADER_WIDTH ) + "] ";
342 }
343
344
345 private Level getLoggerLevel( Logger logger )
346 {
347 Level level = logger.getLevel();
348 if( level != null )
349 {
350 return level;
351 }
352 else
353 {
354 Logger parent = logger.getParent();
355 if( null != parent )
356 {
357 return getLoggerLevel( parent );
358 }
359 else
360 {
361 final String error =
362 "Logging level is not defined.";
363 throw new IllegalStateException( error );
364 }
365 }
366 }
367
368 // ------------------------------------------------------------------------
369 // implementation
370 // ------------------------------------------------------------------------
371
372 /**
373 * Test is the runtime environment is ant.
374 * @return true if ant is visible
375 */
376 private boolean isAnt()
377 {
378 return null != System.getProperty( "ant.home" );
379 /*
380 try
381 {
382 ClassLoader.getSystemClassLoader().loadClass( "org.apache.tools.ant.launch.AntMain" );
383 return true;
384 }
385 catch( Exception e )
386 {
387 return false;
388 }
389 */
390 }
391
392 /**
393 * Return a string representing the number of kilobytes relative to the supplied
394 * total bytes.
395 * @param total the byte value
396 * @return the string to log
397 */
398 private static String getFranctionalValue( int total )
399 {
400 final int offset = 3;
401
402 float realTotal = new Float( total ).floatValue();
403 float realK = new Float( KBYTE ).floatValue();
404 float r = ( realTotal / realK );
405
406 String value = new Float( r ).toString();
407 int j = value.indexOf( "." );
408 if( j > -1 )
409 {
410 int q = value.length();
411 int k = q - j;
412 if( k > offset )
413 {
414 return value.substring( 0, j + offset );
415 }
416 else
417 {
418 return value;
419 }
420 }
421 else
422 {
423 return value;
424 }
425 }
426
427 /**
428 * Internal utility to log a message to system.out.
429 * @param message the message to log
430 */
431 private void log( String message )
432 {
433 m_logger.fine( message );
434 }
435
436 private static final int EIGHT = 8;
437 private static final int PROCESS_HEADER_WIDTH = 6;
438 }
439